package com.xiyuan.smartutils.template.engine;

import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.crypto.MD5;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.xiyuan.smartutils.constants.SignConstants.KiB;
import static com.xiyuan.smartutils.template.engine.TemplateResolver.resolveFile;
import static com.xiyuan.smartutils.template.engine.TemplateResolver.resolveText;

/**
 * the description for class TemplateEngine
 *
 * @author xiyuan-lgz 2024-02-01 @version v1.0.0 新建与整理
 */
@SuppressWarnings("AlibabaConstantFieldShouldBeUpperCase")
public class Templates {
    // 页面结构对象表缓存
    private static final Map<String, Template> cacheMap = new LinkedHashMap<String, Template>(64);
    
    /***********************************/
    // 提供静态调用函数
    /***********************************/
    /**
     * 添加已经编译的页面结构
     */
    public static Template cache(String viewPath, Template template) {
        if (!Validates.isBlank(viewPath)) {cacheMap.put(viewPath, template);}
        cacheMap.put(template.getId(), template);
        return template;
    }
    
    /**
     * 获取已经编译的页面结构
     **/
    public static Template getTemplate(String viewPath) {
        return cacheMap.get(viewPath);
    }
    
    /**
     * 移除已经编译的页面结构
     **/
    public static void removeView(String viewPath) {
        cacheMap.remove(viewPath);
    }
    
    public static Template parseView(String viewPath) throws Exception {
        return resolveFile(viewPath);
    }
    
    private static Result executeView(Template view,
                                      Map<String, Object> paramMap,
                                      List<ParamScope> scopes,
                                      Map<String, Object> innerObjs) {
        
        VariableMap variableMap = null;
        try (StringWriter writer = new StringWriter(32 * KiB); PrintWriter printer = new PrintWriter(writer)) {
            if (view != null) {
                view.execute(new VariableMap(paramMap, scopes, innerObjs), printer);
            }
            if (view.getError() != null) {throw view.getError();}
            return new Result().setResult(writer.toString());
        }
        catch (Throwable e) {
            return new Result().setError(e, e.getMessage());
        }
        finally {
            if (variableMap != null) {variableMap.destroy();}
        }
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap > scopes > innerObjs
     *
     * @param filePath  模板文件地址
     * @param paramMap  变量参数
     * @param scopes    变量参数作用于
     * @param innerObjs 内置对象
     * @return 结果
     */
    public static Result parse(String filePath,
                               Map<String, Object> paramMap,
                               List<ParamScope> scopes,
                               Map<String, Object> innerObjs) {
        try {
            Template view = parseView(filePath);
            return executeView(view, paramMap, scopes, innerObjs);
        }
        catch (Throwable e) {
            return new Result().setError(e, e.getMessage());
        }
        
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap
     *
     * @param filePath 模板文件地址
     * @param paramMap 变量参数
     * @return 结果
     */
    public static Result parse(String filePath, Map<String, Object> paramMap) throws Exception {
        return parse(filePath, paramMap, null, null);
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap > scopes
     *
     * @param filePath 模板文件地址
     * @param paramMap 变量参数
     * @param scopes   变量参数作用于
     * @return 结果
     */
    public static Result parse(String filePath, Map<String, Object> paramMap, List<ParamScope> scopes) throws
                                                                                                       Exception {
        return parse(filePath, paramMap, scopes, null);
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量  > scopes
     *
     * @param filePath 模板文件地址
     * @param scopes   变量参数作用于
     * @return 结果
     */
    public static Result parse(String filePath, List<ParamScope> scopes) throws Exception {
        return parse(filePath, null, scopes, null);
    }
    
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量
     *
     * @param filePath 模板文件地址
     * @return 结果
     */
    public static Result parse(String filePath) throws Exception {
        return parse(filePath, null, null, null);
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap > scopes > innerObjs
     *
     * @param content   模板内容
     * @param paramMap  变量参数
     * @param scopes    变量参数作用于
     * @param innerObjs 内置对象
     * @return 结果
     */
    public static Result parseContent(String content,
                                      Map<String, Object> paramMap,
                                      List<ParamScope> scopes,
                                      Map<String, Object> innerObjs) {
        try {
            if (content == null) return new Result();
            String id = MD5.encodeUTF8(content);
            Template view = parseView(id);
            return executeView(view != null ? view : cache(null, resolveText(id, null, content)),
                               paramMap,
                               scopes,
                               innerObjs);
        }
        catch (Throwable e) {
            return new Result().setError(e, e.getMessage());
        }
        
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap
     *
     * @param content  模板内容
     * @param paramMap 变量参数
     * @return 结果
     */
    public static Result parseContent(String content, Map<String, Object> paramMap) throws Exception {
        return parseContent(content, paramMap, null, null);
    }
    
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > paramMap > scopes
     *
     * @param content  模板内容
     * @param paramMap 变量参数
     * @param scopes   变量参数作用于
     * @return 结果
     */
    public static Result parseContent(String content,
                                      Map<String, Object> paramMap,
                                      List<ParamScope> scopes) throws Exception {
        return parseContent(content, paramMap, scopes, null);
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量 > scopes
     *
     * @param content 模板内容
     * @param scopes  变量参数
     * @return 结果
     */
    public static Result parseContent(String content, List<ParamScope> scopes) throws Exception {
        return parseContent(content, null, scopes, null);
    }
    
    /**
     * 执行表达式。
     * <p>
     * 取值顺序 代码块局部变量 > 页面变量
     *
     * @param content 模板内容
     * @return 结果
     */
    public static Result parseContent(String content) throws Exception {
        return parseContent(content, null, null, null);
    }
    
    public static final class Result {
        private String result;
        private Throwable e;
        
        public String getResult() {
            return result;
        }
        
        public Result setResult(String result) {
            this.result = result;
            return this;
        }
        
        public Throwable getError() {
            return e;
        }
        
        public Result setError(Throwable e, String msg) {
            this.e = e;
            this.result = msg;
            return this;
        }
    }
    
}
